#include "../../videofilters/h26x/h26x-encoder.h"
#include "../../videofilters/h26x/h26x-utils.h"
#include "ohos_video_common.h"
#include "ohos_video_data.h"
#include "video-encoder.h"
#include <multimedia/player_framework/native_avbuffer.h>
#include <multimedia/player_framework/native_avcapability.h>
#include <multimedia/player_framework/native_avcodec_base.h>
#include <multimedia/player_framework/native_avcodec_videoencoder.h>
#include <multimedia/player_framework/native_avformat.h>
#include <string>

class OHOSMediaEncode : public mediastreamer::H26xEncoder {
public:
	~OHOSMediaEncode();

	const std::string &getMime() const {
		return _mime;
	}
	MSVideoSize getVideoSize() const override {
		return _vsize;
	}
	void setVideoSize(const MSVideoSize &vsize) override {
		_vsize = vsize;
	}

	float getFps() const override {
		return _fps;
	}
	void setFps(float fps) override;

	int getBitrate() const override {
		return _bitrate;
	}
	void setBitrate(int bitrate) override;

	bool pixelFormatConversionEnabled() const {
		return _pixelFormatConvertionEnabled;
	}
	void enablePixelFormatConversion(bool enable) {
		_pixelFormatConvertionEnabled = enable;
	}
	void enableOutbufferDequeueLimit(bool enable);
	bool isRunning() override {
		return _isRunning;
	}
	void start() override;
	void stop() override;
	ohos::CodecData *GetCodecData();

	void feed(mblk_t *rawData, uint64_t time, bool requestIFrame = false) override;
	bool fetch(MSQueue *encodedData) override;

	static void OnCodecError(OH_AVCodec *codec, int32_t errorCode, void *userData);
	static void OnCodecFormatChange(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
	static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
	static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);

	int32_t PushInputData(uint8_t *pktData,
	                      size_t dataSize,
	                      int pts,
	                      int flag,
	                      std::chrono::milliseconds waitTime = (std::chrono::milliseconds)0);
	int32_t GetOutputBuffer(ohos::AvBufferInfo &info,
	                        std::chrono::milliseconds waitTime = (std::chrono::milliseconds)0);
	int32_t GetInputBuffer(ohos::AvBufferInfo &info, std::chrono::milliseconds waitTime = (std::chrono::milliseconds)0);

	int32_t FreeInputData(uint32_t index);
	int32_t FreeOutputData(uint32_t index);

protected:
	OHOSMediaEncode(const std::string &mime);
	void createImpl();
	int32_t preConfig();
	int32_t setCallback();
	void configureImpl();
	void RequestIFrame(int32_t value);
	virtual OH_AVFormat *createMediaFormat() const;

	std::unique_ptr<mediastreamer::H26xParameterSetsInserter> _psInserter;
	MSVideoSize _vsize;
	float _fps = 0;
	int _bitrate = 0;
	OH_AVCodec *_impl{nullptr};
	std::unique_ptr<ohos::CodecData> data_{nullptr};
	int _pendingFrames = 0;
	bool _isRunning = false;
	bool _recoveryMode = false;
	bool _pixelFormatConvertionEnabled = true;
	bool _firstImageQueued = false;
	bool _hasOutbufferDequeueLimit = false;

	static const int _timeoutUs = 0;
	static const int32_t _colorFormat = 0x7f420888; // COLOR_FormatYUV420Flexible
	static const int32_t _bitrateMode = 1;          // VBR mode
	static const int32_t _iFrameInterval = 20;      // 20 seconds
	static const int32_t _encodingLatency = 1;
	static const int32_t _priority = 0; // real-time priority
};
